#include "thread_api.h"

struct t_thread_runner{
    thread_func_call func;
    void* param;
    valatile int running;
    thread_id_t thread_id;
};

struct t_thread_runner* t_thread_runner_create(thread_func_call func,void* param)
{
    struct t_thread_runner* runner = MALLOC(sizeof(struct t_thread_runner));
    runner->func = func;
    runner->param = param;
    return runner;
}
void t_thread_runner_destroy(struct t_thread_runner* runner)
{
    t_thread_runner_join(runner);
    FREE(runner);
}
static void start_thread(void* param)
{
    struct t_thread_runner* runner = (struct t_thread_runner*) param;
    while(runner->running ==0)
    {
        t_thread_sleep_ms(10);
    }
    runner->func(runner);
}
int t_thread_runner_start(struct t_thread_runner* runner ,int stack_size)
{
    int reval = 0;
    if(stack_size > 0)
    {
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        pthread_attr_setstacksize(&attr,stack_size);
        retval = pthread_create(&runner->thread_id,&attr,start_thread,runner);
    }
    else
    {
        retval = pthread_create(&runner->thread_id,0,start_thread,runner);
    }
   if(retval > 0)
   {
       return 0;
   }
   return 1;
}
void t_thread_runner_stop(struct t_thread_runner* runner)
{
    runner->running = 0;
}
thread_id_t t_thread_get_id(struct t_thread_runner* runner)
{
    return runner->thread_id;
}
void t_thread_runner_join(struct t_thread_runner* runner)
{
    if(!runner->thread_id)
    {
        return;
    }
    pthread_join(runner->thread_id,0);
    
}
thread_id_t t_thread_get_self()
{
    return pthread_self();
}
void t_thread_sleep_ms(int ms)
{
    usleep(ms * 1000);
}
t_atomic atomic_int(t_atomic* counter)
{
    return __sync_add_and_fetch(counter,1);
}
t_atomic atomic_dec(t_atomic* counter)
{
    return __sync_sub_and_fetch(counter,1);
}
t_atomic atomic_cas(t_atomic* counter,t_atomic target,t_atomic value)
{
    return __sync_val_compare_and_swap(counter,target,value);
}
t_atomic atomic_set(t_atomic* counter,t_atomic value)
{
    return __sync_lock_test_and_set(counter,value);
}
int atomic_zero(t_atomic* counter)
{
    return (*counter = 0);
}

struct t_lock
{
    pthread_mutex_t lock;
}

struct t_lock* t_lock_create()
{
    struct t_lock* lock = MALLOC(sizeof(struct t_lock));
   pthread_mutex_init(&lock->lock,0);
    return lock;
}
void t_lock_destroy(struct t_lock* lock)
{
    pthread_mutex_destroy(&lock->lock);
    FREE(lock);
}

void t_lock_lock(struct t_lock* lock)
{
    pthrea_mutex_lock(&lock->lock);
}
int t_lock_trylock(struct t_lock* lock)
{
    if(pthead_mutex_trylock(&lock->lock) == 0)
    {
        return 0;
    }
    return 1;
}
void t_lock_unlock(struct t_lock* lock)
{
    pthread_mutex_unlock(&lock->lock);
}

struct t_rwlock
{
    pthread_rwlock_t rwlock;
}

struct t_rwlock* t_rwlock_create()
{
    struct t_rwlock* rwlock = MALLOC(sizeof(struct t_rwlock));
    pthread_rwlock_init(&rwlock->rwlock,0);
    return rwlock;
}
void t_rwlock_destroy(struct t_rwlock* rwlock)
{
    pthread_mutex_destroy(&rwlock->rwlock);
    FREE(rwlock);
}
void t_rwlock_rdlock(struct t_rwlock* rwlock)
{
    pthread_rwlock_rdlock(&rwlock->rwlock);
}
void t_rwlock_rdunlock(struct t_rwlock* rwlock)
{
    pthread_rwlock_unlock(&rwlock->rwlock);
}
void t_rwlock_wrlock(struct t_rwlock* rwlock)
{
    pthread_rwlock_wrlock(&rwlock->rwlock);
}
void t_rwlock_wrunlock(struct t_rwlock* rwlock)
{
    pthread_rwlock_unlock(&rwlock->rwlock);
}

struct t_cond
{
    pthread_cond_t cond;
}

struct t_cond* t_cond_create()
{
    struct t_cond* cond = MALLOC(sizeof(struct t_cond));
    if(pthread_cond_init(&cond->cond,0))
    {
        FREE(cond);
        return NULL;
    }
    return cond;
}
void t_cond_destroy(struct t_cond* cond)
{
    pthread_cond_destroy(cond->cond);
    FREE(cond);
}
void t_cond_wait(struct t_cond* cond,struct t_lock* lock)
{
  pthread_cond_wait(&cond->cond,&lock->lock);
}
void t_cond_signal(struct t_cond* cond)
{
   pthread_cond_signal(&cond->cond);
}